/**
 * Copyright (C) 2011 Steve McLeod (http://stackoverflow.com/users/2959/steve-mcleod)
 *
 * Source:
 * http://stackoverflow.com/questions/7745087
 *
 * License: http://creativecommons.org/licenses/by-sa/3.0/
 */
package org.languagetool.gui;

import javax.swing.*;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.parser.ParserDelegator;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;

/**
 * Keep line breaks when copying from JTextPane.
 */
class RetainLineBreakTransferHandler extends TransferHandler {

  @Override
  protected Transferable createTransferable(JComponent c) {
    final JEditorPane pane = (JEditorPane) c;
    final String htmlText = pane.getText();
    final String plainText = extractText(new StringReader(htmlText));
    return new MyTransferable(plainText, htmlText);
  }

  private String extractText(Reader reader) {

    final StringBuilder result = new StringBuilder();
    final HTMLEditorKit.ParserCallback parserCallback = new HTMLEditorKit.ParserCallback() {
      @Override
      public void handleText(final char[] data, final int pos) {
        result.append(data);
      }
      @Override
      public void handleStartTag(HTML.Tag tag, MutableAttributeSet attribute, int pos) {
      }
      @Override
      public void handleEndTag(HTML.Tag tag, final int pos) {
      }
      @Override
      public void handleSimpleTag(HTML.Tag tag, MutableAttributeSet a, final int pos) {
        if (tag.equals(HTML.Tag.BR)) {
          result.append("\n");
        }
      }
      @Override
      public void handleComment(final char[] data, final int pos) {
      }
      @Override
      public void handleError(final String errMsg, final int pos) {
      }
    };
    try {
      new ParserDelegator().parse(reader, parserCallback, true);
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
    return result.toString();
  }


  @Override
  public void exportToClipboard(JComponent comp, Clipboard clip, int action) throws IllegalStateException {
    if (action == COPY) {
      clip.setContents(this.createTransferable(comp), null);
    }
  }

  @Override
  public int getSourceActions(JComponent c) {
    return COPY;
  }

}

class MyTransferable implements Transferable {

  private static final DataFlavor[] supportedFlavors;

  static {
    try {
      supportedFlavors = new DataFlavor[]{
              new DataFlavor("text/html;class=java.lang.String"),
              new DataFlavor("text/plain;class=java.lang.String")
      };
    } catch (ClassNotFoundException e) {
      throw new ExceptionInInitializerError(e);
    }
  }

  private final String plainData;
  private final String htmlData;

  public MyTransferable(String plainData, String htmlData) {
    this.plainData = plainData;
    this.htmlData = htmlData;
  }

  @Override
  public DataFlavor[] getTransferDataFlavors() {
    return supportedFlavors;
  }

  @Override
  public boolean isDataFlavorSupported(DataFlavor flavor) {
    for (DataFlavor supportedFlavor : supportedFlavors) {
      if (supportedFlavor == flavor) {
        return true;
      }
    }
    return false;
  }

  @Override
  public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
    if (flavor.equals(supportedFlavors[0])) {
      return htmlData;
    }
    if (flavor.equals(supportedFlavors[1])) {
      return plainData;
    }
    throw new UnsupportedFlavorException(flavor);
  }
}
